Public Class SharedList (Of T)
  Implements IList(Of T)
  Implements IDisposable

  Dim _lockStrategy As ILockStrategy
  Dim _list As List(Of T) = New List(Of T)

  Public Sub New()
    Me.New(LockingStrategy.ReaderWriter)
  End Sub

  Public Sub New(ByVal strategy As LockingStrategy)
    _lockStrategy = LockingStrategyFacotry.Create(strategy)
  End Sub

  Friend ReadOnly Property BackingList As IList(Of T)
    Get
      Return _list
    End Get
  End Property

  Public Function GetReadLock() As ISharedCollectionLock
    EnsureNotDisposed()
    Return _lockStrategy.GetReadLock()
  End Function

  Public Function GetWriteLock() As ISharedCollectionLock
    EnsureNotDisposed()
    Return _lockStrategy.GetWriteLock()
  End Function

  Private Sub EnsureReadAccess()
    If Not (_lockStrategy.ThreadCanRead) Then
      Throw New ReadLockRequiredException()
    End If
  End Sub

  Private Sub EnsureWriteAccess()
    If Not _lockStrategy.ThreadCanWrite Then
      Throw New WriteLockRequiredException()
    End If
  End Sub

  Public Sub Add(ByVal item As T) Implements ICollection(Of T).Add
    EnsureNotDisposed()
    EnsureWriteAccess()
    _list.Add(item)
  End Sub

  Public Sub Clear() Implements ICollection(Of T).Clear
    EnsureNotDisposed()
    EnsureWriteAccess()
    _list.Clear()
  End Sub

  Public Function Contains(ByVal item As T) As Boolean Implements ICollection(Of T).Contains
    EnsureNotDisposed()
    EnsureReadAccess()
    Return _list.Contains(item)
  End Function

  Public Sub CopyTo(ByVal array() As T, ByVal arrayIndex As Integer) Implements ICollection(Of T).CopyTo
    EnsureNotDisposed()
    EnsureReadAccess()
    _list.CopyTo(array, arrayIndex)
  End Sub

  Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count
    Get
      EnsureNotDisposed()
      EnsureReadAccess()
      Return _list.Count
    End Get
  End Property

  Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly
    Get
      EnsureNotDisposed()
      EnsureReadAccess()
      Return CType(_list, ICollection(Of T)).IsReadOnly
    End Get
  End Property

  Public Function Remove(ByVal item As T) As Boolean Implements ICollection(Of T).Remove
    EnsureNotDisposed()
    EnsureWriteAccess()
    Return _list.Remove(item)
  End Function

  Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
    EnsureNotDisposed()
    EnsureReadAccess()
    Return _list.GetEnumerator()
  End Function

  Public Function IndexOf(ByVal item As T) As Integer Implements IList(Of T).IndexOf
    EnsureNotDisposed()
    EnsureReadAccess()
    Return _list.IndexOf(item)
  End Function

  Public Sub Insert(ByVal index As Integer, ByVal item As T) Implements IList(Of T).Insert
    EnsureNotDisposed()
    EnsureWriteAccess()
    _list.Insert(index, item)
  End Sub

  Default Public Property Item(ByVal index As Integer) As T Implements IList(Of T).Item
    Get
      EnsureNotDisposed()
      EnsureReadAccess()
      Return _list(index)
    End Get
    Set(ByVal value As T)
      EnsureNotDisposed()
      EnsureWriteAccess()
      _list(index) = value
    End Set
  End Property

  Public Sub RemoveAt(ByVal index As Integer) Implements IList(Of T).RemoveAt
    EnsureNotDisposed()
    EnsureWriteAccess()
    _list.RemoveAt(index)
  End Sub

  Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
    Return GetEnumerator()
  End Function

#Region "IDisposable Support"

  Private _isDisposed As Boolean
  ' To detect redundant calls

  Public Sub EnsureNotDisposed()
    If _isDisposed Then
      Throw New ObjectDisposedException("SharedList")
    End If
  End Sub

  ' IDisposable
  Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    If Not Me._isDisposed Then
      If disposing Then
        ' dispose managed state (managed objects).
      End If

      _lockStrategy.Dispose()
      _lockStrategy = Nothing
    End If
    Me._isDisposed = True
  End Sub

  Protected Overrides Sub Finalize()
    Dispose(False)
    MyBase.Finalize()
  End Sub

  Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub

#End Region
End Class